Teleport Connect headless approval - Skip Confirmation#29875
Conversation
|
@gzdunek @ravicious Any idea why I am getting |
21e0415 to
ffd0692
Compare
ffd0692 to
c15597c
Compare
No, it is a Node.js thing, and it is not passed to the renderer (or, in other words, the browser window). |
b32bd00 to
b9cd730
Compare
There was a problem hiding this comment.
@ravicious @gzdunek For some reason, this OnApprove call results in an infinite loop, sending countless headless approval requests to the tshd daemon and overloading the yubikey. I have no idea why this would be an infinite loop while the on button press below works perfectly fine. Any ideas?
There was a problem hiding this comment.
That's because the body of a component function, HeadlessPrompt, is executed on each render and a component gets rendered each time you update it's state. So you end up with an infinite loop.
Try this patch:
Patch
diff --git a/web/packages/teleterm/src/ui/HeadlessAuthn/HeadlessAuthentication.tsx b/web/packages/teleterm/src/ui/HeadlessAuthn/HeadlessAuthentication.tsx
index 08da0c1aa6..fc73d9b1c3 100644
--- a/web/packages/teleterm/src/ui/HeadlessAuthn/HeadlessAuthentication.tsx
+++ b/web/packages/teleterm/src/ui/HeadlessAuthn/HeadlessAuthentication.tsx
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-import React, { useRef } from 'react';
+import React, { useRef, useEffect } from 'react';
import { useAsync } from 'shared/hooks/useAsync';
@@ -69,6 +69,12 @@ export function HeadlessAuthentication(props: HeadlessAuthenticationProps) {
}
}
+ useEffect(() => {
+ if (props.skipConfirm && updateHeadlessStateAttempt.status === '') {
+ handleHeadlessApprove();
+ }
+ }, []);
+
return (
<HeadlessPrompt
cluster={cluster}
diff --git a/web/packages/teleterm/src/ui/HeadlessAuthn/HeadlessPrompt/HeadlessPrompt.tsx b/web/packages/teleterm/src/ui/HeadlessAuthn/HeadlessPrompt/HeadlessPrompt.tsx
index f1da2f1bd8..b0294cb162 100644
--- a/web/packages/teleterm/src/ui/HeadlessAuthn/HeadlessPrompt/HeadlessPrompt.tsx
+++ b/web/packages/teleterm/src/ui/HeadlessAuthn/HeadlessPrompt/HeadlessPrompt.tsx
@@ -52,13 +52,9 @@ export function HeadlessPrompt({
updateHeadlessStateAttempt,
onCancel,
}: HeadlessPromptProps) {
- const [waitForMfa, setWaitForMfa] = useState(false);
-
- // skip to MFA confirmation step.
- if (skipConfirm) {
- setWaitForMfa(true);
- onApprove();
- }
+ // skipConfirm automatically attempts to approve a headless auth attempt,
+ // so let's show waitForMfa from the very beginning in that case.
+ const [waitForMfa, setWaitForMfa] = useState(skipConfirm);
return (
<DialogConfirmationThere was a problem hiding this comment.
Ah I suspected it was something like that but had no idea how to fix it, thanks!
ravicious
left a comment
There was a problem hiding this comment.
It should be good to go after implementing the changes I mentioned.
There was a problem hiding this comment.
That's because the body of a component function, HeadlessPrompt, is executed on each render and a component gets rendered each time you update it's state. So you end up with an infinite loop.
Try this patch:
Patch
diff --git a/web/packages/teleterm/src/ui/HeadlessAuthn/HeadlessAuthentication.tsx b/web/packages/teleterm/src/ui/HeadlessAuthn/HeadlessAuthentication.tsx
index 08da0c1aa6..fc73d9b1c3 100644
--- a/web/packages/teleterm/src/ui/HeadlessAuthn/HeadlessAuthentication.tsx
+++ b/web/packages/teleterm/src/ui/HeadlessAuthn/HeadlessAuthentication.tsx
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-import React, { useRef } from 'react';
+import React, { useRef, useEffect } from 'react';
import { useAsync } from 'shared/hooks/useAsync';
@@ -69,6 +69,12 @@ export function HeadlessAuthentication(props: HeadlessAuthenticationProps) {
}
}
+ useEffect(() => {
+ if (props.skipConfirm && updateHeadlessStateAttempt.status === '') {
+ handleHeadlessApprove();
+ }
+ }, []);
+
return (
<HeadlessPrompt
cluster={cluster}
diff --git a/web/packages/teleterm/src/ui/HeadlessAuthn/HeadlessPrompt/HeadlessPrompt.tsx b/web/packages/teleterm/src/ui/HeadlessAuthn/HeadlessPrompt/HeadlessPrompt.tsx
index f1da2f1bd8..b0294cb162 100644
--- a/web/packages/teleterm/src/ui/HeadlessAuthn/HeadlessPrompt/HeadlessPrompt.tsx
+++ b/web/packages/teleterm/src/ui/HeadlessAuthn/HeadlessPrompt/HeadlessPrompt.tsx
@@ -52,13 +52,9 @@ export function HeadlessPrompt({
updateHeadlessStateAttempt,
onCancel,
}: HeadlessPromptProps) {
- const [waitForMfa, setWaitForMfa] = useState(false);
-
- // skip to MFA confirmation step.
- if (skipConfirm) {
- setWaitForMfa(true);
- onApprove();
- }
+ // skipConfirm automatically attempts to approve a headless auth attempt,
+ // so let's show waitForMfa from the very beginning in that case.
+ const [waitForMfa, setWaitForMfa] = useState(skipConfirm);
return (
<DialogConfirmation…al state. This makes it possible to reject a headless authentication when it skips the initial confirmation step.
885be29 to
c64fdd1
Compare
* Support TELEPORT_HEADLESS_SKIP_CONFIRM env flag in teleport connect. * Replace reject button with cancel button that persists through approval state. This makes it possible to reject a headless authentication when it skips the initial confirmation step. * Add headlessSkipConfirm config option. * Apply changes from CR.
* Support TELEPORT_HEADLESS_SKIP_CONFIRM env flag in teleport connect. * Replace reject button with cancel button that persists through approval state. This makes it possible to reject a headless authentication when it skips the initial confirmation step. * Add headlessSkipConfirm config option. * Apply changes from CR.
Updates Teleport Connect headless approval flow to skip the confirmation step (Approve/Cancel) and go straight to prompting for MFA in the background when the
headless.skipConfirmconfig option is set totrue.Docs will be added in a follow up PR.